/**
 * 
 */
package ikeuilib;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.Date;
import java.util.EventObject;

import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.CellEditorListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

/**
 * ＪＴＡＢＬＥにチェックボックスやコンボボックスなどのコンポーネントを表示させて編集できるクラス。
 * プロパティの設定などにつかう。
 * @author ikechan
 *
 */
public class TableParamBasic extends JTable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	protected TableCellRenderer genericRenderer = new GenericCellRenderer();
	protected TableCellEditor genericEditor = new GenericCellEditor();
	/**
	 * @param model
	 */
	public TableParamBasic(DefaultTableModel model) {
		super(model);
		// Ｄ＆Ｄの列の入れ替えを禁止する。
		getTableHeader().setReorderingAllowed(false);
	}
	/**
	 * 名前からオブジェクトを得る。
	 * @param name
	 * @return
	 */
	public Object getValue(String name){
		editingStopped(null);
		int count = getRowCount();
		for(int i=0;i<count;i++){
			String n  = (String)getValueAt(i, 0);
			if(n.compareTo(name)==0){
				return getValueAt(i,1);
			}
		}
		return null;
	}
	/**
	 * インデックスからval　を得る
	 * @param idx
	 * @return
	 */
	public Object getValue(int idx){
		editingStopped(null);
		return getValueAt(idx,1);
	}
	/**
	 * インデックスからItem　を得る
	 * @param idx
	 * @return
	 */
	public Object getItem(int idx){
		return getValueAt(idx,0);
	}

	/**
	 * セルレンダラーを得るために呼び出される。
	 */
	public TableCellRenderer getCellRenderer(int row, int col) {
		
		TableCellRenderer renderer;
		Object o = getValueAt(row, col);
		// 指定されたセルにSwingコンポーネントが置かれている場合には、
		// 汎用セルレンダラー[GenericCellRenderer]のオブジェクトを返す。
		// それ以外の場合には、そのセルに対応しているデフォルトのセルレンダラーを返す
		if(o instanceof JComponent) {
			renderer = genericRenderer;
		}else if(o instanceof Boolean) {
			renderer = genericRenderer;
		}else if(o instanceof Number) {
			renderer = genericRenderer;
		}else if(o instanceof Font) {
			renderer = genericRenderer;
		}else if(o instanceof Date) {
			renderer = genericRenderer;
		}else if(o instanceof Color) {
			renderer = genericRenderer;
		} else {
			
			renderer = super.getCellRenderer(row, col);
		}
		return renderer;
	}
	
	
	/**
	 *  セルエディターを得るために呼びさされる。
	 */
	public TableCellEditor getCellEditor(int row, int col) {
		TableCellEditor editor;
		Object o = getValueAt(row, col);
		if( o instanceof JComponent) {
			editor = genericEditor;
		}else if(o instanceof Boolean) {
			editor = genericEditor;
		}else if(o instanceof Number) {
			editor = genericEditor;
		}else if(o instanceof Color) {
			editor = genericEditor;
		}else if(o instanceof Date) {
			editor = genericEditor;
		}else if(o instanceof Font) {
			editor = genericEditor;
		} else {
			editor = super.getCellEditor(row, col);
		}
		return editor;
	}

	////////////////////////////////////////////////////////////
	// セルレンダラークラス
	////////////////////////////////////////////////////////////
	protected class GenericCellRenderer extends DefaultTableCellRenderer implements TableCellRenderer {
		private static final long serialVersionUID = 1L;
		private TableColorRenderer color;
		private TableFontRenderer font;
		private DateCellRenderer date;
		
		public GenericCellRenderer(){
			color=new TableColorRenderer(true);
			font=new TableFontRenderer(true);
			date=new DateCellRenderer(true);
		}
		/**
		 * レンダラコンポーネント取得
		 * @param JTable 対象テーブル
		 * @param Object 表示する値
		 * @param boolean 選択されているかどうか
		 * @param boolean フォーカスが当たっているかどうか
		 * @param int 対象行番号
		 * @param int 対象カラム番号
		 * @return Component レンダラコンポーネント
		 */
		
		 // getTableCellRendererComponent()に渡されてきたコンポーネントを、
		 // このメソッドの戻り値として返す。
		 // セルに置けれているSwingコンポーネントを、
		 // そのままセルレンダラーのコンポーネントとして使うことになる。
		public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected, boolean hasFocus,int row, int column){
			
			Component ret = null;
			if(	value instanceof Boolean){
				JCheckBox b=new JCheckBox();
				b.setBackground(Color.WHITE);
				b.setSelected(((Boolean)value).booleanValue());
				ret= b;
			}else if(value instanceof Color){
				ret = color.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
			}else if(value instanceof Date){
				ret = date.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
			}else if(value instanceof Font){
				font.setBackground(Color.WHITE);
				ret = font.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
			}else if(value instanceof JComboBox){
				JComboBox c=(JComboBox)value;
				ret = super.getTableCellRendererComponent(table, c.getSelectedItem(), isSelected, hasFocus, row, column);
			}else if(value instanceof JComponent){
				ret =  (JComponent)value;
			}else{
				ret = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
			}
			// テーブルの各行の高さを調整する。
			Dimension d = ret.getPreferredSize();
			if(table.getRowHeight(row) < d.height) {
				table.setRowHeight(row, d.height);
			}
			
			return ret;
		}
	}

	////////////////////////////////////////////////////////////
	// セルエディタークラス
	////////////////////////////////////////////////////////////
	protected class GenericCellEditor extends DefaultCellEditor /*AbstractCellEditor*//*implements TableCellEditor*/ {
		
		private Component comp;
		private TableCellEditor color;
		private TableCellEditor font;
		private CalendarDialog cal;
		private Object val;

		public GenericCellEditor(){
			super(new JTextField());
			color=new TableColorEditor();
			font=new TableFontEditor();
			cal=new CalendarDialog(JOptionPane.getRootFrame());
			// クリック一回で編集開始
			setClickCountToStart(1);
		}		
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		// protected JComponent c = null;
		
		// このコンポーネントをインスタンス変数に保管しておき、
		// getCellEditorValue()が呼ばれるとき(セルの編集終了時)に
		// このコンポーネントを返す。
		// これにより、編集終了時に、コンポーネントが消失してしまうことを防ぐ。
		public Object getCellEditorValue() {
		
			if(val instanceof Number){
				try{
					if(val instanceof Integer){
						return Integer.parseInt(super.getCellEditorValue().toString());
					}else if(val instanceof Float){
						return Float.parseFloat(super.getCellEditorValue().toString());
					}else if(val instanceof Double){
						return Double.parseDouble(super.getCellEditorValue().toString());
					}else if(val instanceof Long){
						return Long.parseLong(super.getCellEditorValue().toString());
					}else{
						return Double.parseDouble(super.getCellEditorValue().toString());
					}
				}catch(NumberFormatException ne){
					JOptionPane.showMessageDialog(comp,"NumberFormatException","",JOptionPane.ERROR_MESSAGE);
					return val;
				}
			}else if(val instanceof Color){
				return color.getCellEditorValue();
			}else if(val instanceof Font){
				return font.getCellEditorValue();
			}else if(val instanceof Date){
				return cal.getDate();
			}else{
				if(comp instanceof JCheckBox){
					if(((JCheckBox)comp).isSelected()){
						return Boolean.TRUE;
					}else{
						return Boolean.FALSE;
					}
				}else if(comp instanceof JTextField){
					return ((JTextField)comp).getText();
				}else if(comp instanceof JComboBox){
					return (JComboBox)comp;
				}else if(comp instanceof JButton){
					return (JButton)comp;
				}else if(comp instanceof JLabel){
					return (JLabel)comp;
				}else{
					return super.getCellEditorValue();
				}
			}
		//	return c;
		}
		
		/**
		 * レンダラコンポーネント取得
		 * @param JTable 対象テーブル
		 * @param Object 表示する値
		 * @param boolean 選択されているかどうか
		 * @param boolean フォーカスが当たっているかどうか
		 * @param int 対象行番号
		 * @param int 対象カラム番号
		 * @return Component レンダラコンポーネント
		 */
		public Component getTableCellEditorComponent(JTable	table,Object value,boolean isSelected, int row,int column){
			if(value instanceof Boolean){
				JCheckBox b=new JCheckBox();
				b.setBackground(Color.WHITE);
				b.setSelected(((Boolean)value).booleanValue());
				comp=b;
				val=value;
				return comp;
			}else if(value instanceof Font){
				val=value;
				return font.getTableCellEditorComponent(table, value, isSelected, row, column);
			}else if(value instanceof Date){
				final JTable tt=table;
				final int rr=row;
				final int cc=column;
				final Object xx=value;
				JButton tmp=new JButton(((Date)value).toString());
				tmp.addActionListener(new ActionListener(){
					@Override
					public void actionPerformed(ActionEvent arg0) {
						Date dd=(Date)tt.getModel().getValueAt(rr, cc);
						cal.setDate(dd);
						cal.setLocationRelativeTo(tt);
						cal.setVisible(true);
						Date d=cal.getDate();
						///System.out.println("Date dialog end");
						if(d!=null){
							val=d;
						}else{
							val=xx;
						}
						editingStopped(null);

					}
				});
				return tmp;
			}else if(value instanceof Color){
				val=value;
				return color.getTableCellEditorComponent(table, value, isSelected, row, column);
			}else if(value instanceof JButton){
				JButton tmp=new JButton(((JButton)value).getText());
				ActionListener[] ac=((JButton)value).getActionListeners();
				for(int i=0;i<ac.length;i++){
					tmp.addActionListener(ac[i]);
				}
				comp=tmp;
				val=value;
				return comp;
			}else if(value instanceof JComboBox){
				JComboBox tmp=new JComboBox(((JComboBox)value).getModel());
				ActionListener[] ac=((JComboBox)value).getActionListeners();
				for(int i=0;i<ac.length;i++){
					tmp.addActionListener(ac[i]);
				}
				comp=tmp;
				val=value;
				return comp;
			}else if(value instanceof JLabel){
				JLabel tmp=(JLabel)value;
				comp=tmp;
				val=tmp;
				return comp;
			}else{
				val=value;
				comp=super.getTableCellEditorComponent(table,value,isSelected,row,column);
				return comp;
			}			
//			c = (JComponent)value;
//			return c;
		}
	}
	////////////////////////////////////////////////////////////
	// テストベンチ
	////////////////////////////////////////////////////////////
	public static void main(String[] arg){
		EventQueue.invokeLater( new Runnable() {
			TableParamBasic me;
			public void run() {
				JFrame frame = new JFrame();
				frame.setSize( 400, 300 );
				frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
				// 場所
				frame.setLocationByPlatform( true );
				// タイトル
				frame.setTitle( "Hello, Swing!" );

				frame.setVisible(true);
				
				final DefaultTableModel model=new DefaultTableModel(){
					private static final long serialVersionUID = 1L;
					// ０列目が名称で、１列目がデータ、データのみが編集可能とする
					@Override
					public boolean isCellEditable(int arg0, int arg1) {
						return (arg1==1);
					}
				};
				
				
				String[] colnames = { "Name", "Value"};
				model.setColumnCount(colnames.length);
				model.setRowCount(7);
				model.setColumnIdentifiers(colnames);

				me = new TableParamBasic(model);
				me.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
				JScrollPane scroll = new JScrollPane(me);
				
				JPanel p = new JPanel();
				p.setLayout(new BorderLayout());
				p.add(scroll,BorderLayout.CENTER);
				

				me.setValueAt(false, 0, 1);
				me.setValueAt("Boolean", 0, 0);
				
				
				Object[] ob=  {"ABC","DEF"};
				JComboBox box = new JComboBox(ob);
				box.setBorder(BorderFactory.createEmptyBorder()); 
				me.setValueAt(box, 1, 1);
				me.setValueAt("Combo",1, 0);
				
				me.setValueAt(new String("test"), 2, 1);
				me.setValueAt("Str",2, 0);
				
				me.setValueAt(new Integer(456), 3, 1);
				me.setValueAt("Int",3, 0);
				
				me.setValueAt(new Color(0), 4, 1);
				me.setValueAt("Color",4, 0);
				
				Font f = new Font("Dialog",Font.PLAIN,14);
				me.setValueAt(f, 5, 1);
				me.setValueAt("Font",5, 0);

				Date dt = new Date();
				me.setValueAt(dt, 6, 1);
				me.setValueAt("Date",6, 0);
				
				JButton btn = new JButton("OK");
				p.add(btn,BorderLayout.SOUTH);
				btn.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						// すべてを列挙してみる
						int max = me.getRowCount();
						for(int i=0;i<max;i++){
							Object o = me.getValue(i);
							System.out.println("Index = " + i + " Object " + o);
						}

						 // OKを押したら 、JTableの編集を強制的に終了させて、入力を無視しないようにする。
						//me.editingStopped(null);
//						Object o = me.getValue("Boolean");
//						if(o instanceof Boolean){
//							boolean b = (Boolean)o;
//							System.out.println("Boolean "  + b);
//						}
//						o = me.getValue("Combo");
//						if(o instanceof JComboBox){
//							JComboBox in = (JComboBox)o;
//							String s = (String)in.getSelectedItem();
//							System.out.println("Combo " + s);
//						}
//						o = me.getValue("Int");
//						if(o instanceof Integer){
//							Integer in = (Integer)o;
//							System.out.println("Int " + in);
//						}
//						o = me.getValue("Str");
//						if(o instanceof String){
//							System.out.println("Str " +  o);
//						}
//						o = me.getValue("Color");
//						if(o instanceof Color){
//							System.out.println("Color " +  o);
//						}
//						o = me.getValue("Font");
//						if(o instanceof Font){
//							System.out.println("Font " +  o);
//						}
//						o = me.getValue("Date");
//						if(o instanceof Date){
//						}
					}
				});
				frame.add(p);
			}
        } );	
		
	}
	
}
